// Notation of position:
// ====================
// Height/Width (H/W) Head/Tail (H/T) [Radius (R)]
// 
//            HH/WHR                HH/WTR
// HH/WH   +----------------------------+ HH/WT
// TL      | /                        \ | 
// HHR/WH  |/                          \| HHR/WT
//         |                            |
//         |                            |
//         |                            |
//         |                            |
//         |                            |
//         |                            |
// HTR/WH  |\                          /| HTR/WT
//         | \                        / |
// HT/WH   +----------------------------+ HT/WT
//            HT/WHR                HT/WTR
// 

// Control Point Adjusting:
// 
// Adjust the "sharpness" of the rounded corner by creating overhead of control points

const control = (x, y, inc, dir) => {
    const [w1,    h1,   w2,   h2] = {
      TL: [0,   -inc, -inc,    0],
      TR: [inc,    0,    0, -inc],
      BR: [0,    inc, inc,     0],
      BL: [-inc,   0,    0,  inc]
    }[dir];
    return `${x + w1} ${y + h1} ${x + w2} ${y + h2}`
  }
  
  const curveTo =(dir, type, cornerW, cornerH, radW, radH, inc) => {
    return type === 'C'
    ? `C ${control(cornerW, cornerH, inc, dir)} ${ radW } ${ radH }`
    : `L ${ cornerW } ${ cornerH } L ${ radW } ${ radH  }`
  }
  
  const cuboxPath = (size, radius, rawStrokeWidth=0, initCorners={}) => {
  
    const {height: h, width: w} = size;
    
    const {max, min} = Math;
      
    // N.B:
    // 
    // (tl;dr) DO NOT MESS UP WITH THE MAGIC NUMBERS BELOW. 
    // 
    // You should be aware of the difference of corner curvature on the stroke
    // of the box. It's been proven that you cannot calculate the "edge" of a
    // bezier stroke with merely the curve equation and a "width". The edge of
    // a cubic bezier stroke is not cubic anymore -- it's actually a 10-order
    // curve, and can only be approximated.
    // 
    // Pomax provides extensive material about Bezier curve. Worth reading.
    // https://pomax.github.io/bezierinfo/
    // 
    // What I did here is a very naive approach. The box should behave same as
    // the CSS property "box-sizing: border-box", i.e. the border is part of
    // the box when calculating box size. Thus the property "cornerRadius" of
    // the box are always about the outer edge of the stroke.
    // 
    // Conceivably the corner curvature of the inner edge of the stroke gets
    // greater (the corner gets sharper), and this is an empirical estimation
    // of the relationship between the sharpness of inner corner curvature and
    // the stroke width.
    // 
    // In very rare cases, you would draw some blocks with this component, and
    // you will probably draw stroke with width larger than a pixel. In most
    // cases, you don't. The parameters below works perfectly for pixel-width
    // stroke. So no need to change them. If you find that the stroke width looks
    // unevenly,  especially for the thick stroke, it would be better for you
    // to draw your own SVG.  
  
    const radi = max(min(radius, min(w, h) / 2), 15);  
      const HHR = radi;
      const WHR = radi;
      const HTR = h - HHR;
      const WTR = w - WHR;
  
    const off = min(radi, rawStrokeWidth);
      const HH = off;
      const WH = off;
      const HT = h - HH;
      const WT = w - WH;
  
      const inc = min( radi / off , off) / 2;
  
    const corners = {TL:'C', TR:'C', BR:'C', BL:'C', ...initCorners};
  
    return `M ${WH} ${HHR}
     ${curveTo('TL', corners['TL'], WH, HH, WHR, HH , inc, )} L ${ WTR } ${ HH  }
     ${curveTo('TR', corners['TR'], WT, HH, WT,  HHR, inc, )} L ${ WT  } ${ HTR }
     ${curveTo('BR', corners['BR'], WT, HT, WTR, HT , inc, )} L ${ WHR } ${ HT  }
     ${curveTo('BL', corners['BL'], WH, HT, WH,  HTR, inc, )} L ${ WH  } ${ HHR }`
  }
  
  export default cuboxPath;